
#include "LevelManager.h"
#include "EmitterManager.h"
#include "ObjectManager.h"
#include "Camera.h"
#include "HelpInfoManager.h"


#include "GamePlayState.h"

#include "Button.h"
#include "ConveyorBelt.h"
#include "GameObject.h"
#include "Gate.h"
#include "Hologram.h"
#include "ConditionalGate.h"
#include "IceBlock.h"
#include "IceLayer.h"
#include "MetalBox.h"
#include "MovingPlatform.h"
#include "Saw.h"
#include "StaticObjects.h"
#include "Tile.h"
#include "WoodBox.h"
#include "FlameJet.h"
#include "CheckPoint.h"
#include "MachineObj.h"
#include "RadiationBarrel.h"
#include "LaserEmitter.h"
#include "LaserReflector.h"
#include "LaserReceiver.h"
#include "Crusher.h"
#include "Generator.h"
#include "Fan.h"
#include "Water.h"

#include "TripWire.h"

#include "SecurityCannon.h"


#include <fstream>
#include <map>

#include "../TinyXML/tinyxml.h"

unsigned int LevelManager::curLevel = 0;

string GetObjectData(const char* data, string tag);
int GetObjectDataInt(const char* data, string tag);
bool GetObjectDataBool(const char* data, string tag);

// Constructor
LevelManager::LevelManager(void)
{
	// The XML file containing all file names of level data.
	TiXmlDocument document;
	bool loadedWell = (document.LoadFile("XML\\levels\\leveldata.xml"));
	assert(loadedWell == true &&  "'level data.xml' is missing from the XML folder.");

	// The root element of document.
	TiXmlElement* root = document.RootElement();

	TiXmlElement* levelElement = root->FirstChildElement("level");

	// Get an instance to the Object Manager
	objectManager = ObjectManager::GetInstance();

	totalLevels = 0;

	while(levelElement != nullptr)
	{
		// At the filename to the vector of filepaths.
		//levelPaths.push_back(levelElement->GetText());
		//levelPaths[levelPaths.size() - 1].insert(0, "XML\\levels\\");
		levelPaths.push_back("XML\\levels\\");
		levelPaths[levelPaths.size() - 1] += levelElement->GetText();

		levelElement = levelElement->NextSiblingElement("level");

		++totalLevels;
	}

	//totalLevels = levelPaths.size();
}

// Destructor
LevelManager::~LevelManager(void)
{
}

// LoadLevel
//	- Unloads the currently loaded level (if any) and loads
//	  the level stored at the specified index.
//	- If the index is out of range, the current level is not
//	  unloaded, and everything is ignored.
void LevelManager::LoadLevel(unsigned int level)
{
	//temp debug
	//unsigned int* temp = &curLevel;

	// If the level does not exist, return from the function and do nothing.
	if(level >= totalLevels)
		return;

	// Get the filename for the level to load.
	string filename = levelPaths[level];

	// Create the TinyXML document.
	TiXmlDocument document;

	// If the file loads successfully, unload the current level and
	// begin creating and loading objects from the XML.
	if( document.LoadFile(filename.c_str()) )
	{
		// Unload the current level.
		UnloadLevel( );

		// Element pointers for loading in different items.
		TiXmlElement* rootElement = document.RootElement( );
		TiXmlElement* objectElement = nullptr;
		TiXmlElement* collisionElement = nullptr;
		TiXmlElement* tileMapElement = nullptr;
		TiXmlElement* emitterElement = nullptr;
		TiXmlElement* spawnLocationElement = nullptr;

		// Initialize the element pointers.
		if(rootElement != nullptr)
		{
			objectElement = rootElement->FirstChildElement("object");
			collisionElement = rootElement->FirstChildElement("collision");
			tileMapElement = rootElement->FirstChildElement("tileMap");
			emitterElement = rootElement->FirstChildElement("emitter");
			spawnLocationElement = rootElement->FirstChildElement("spawnLocation");
		}

		//////////////////////////////////////////////////
		// Load the player's spawn location:
		if(spawnLocationElement != nullptr)
		{
			int spawnPosX, spawnPosY;

			spawnLocationElement->Attribute("x", &spawnPosX);
			spawnLocationElement->Attribute("y", &spawnPosY);

			GamePlayState::GetInstance()->GetPlayer()->SetStartPosition((float)spawnPosX, (float)spawnPosY);
			GamePlayState::GetInstance()->GetPlayer()->SetCheckPointPosition((float)spawnPosX, (float)spawnPosY);
			GamePlayState::GetInstance()->GetPlayer()->ResetToCheckPoint();
		}

		//////////////////////////////////////////////////
		// Load objects:
		while(objectElement != nullptr)
		{
			// Get the gameobject's ID. This determines what game object to create.
			string id = objectElement->Attribute("id");

			int x, y;
			int width, height;
			string tag;
			string data;
			bool hasWaypoints;
			bool useEvents;
			RECT hitBox;

			// Load the position of the object.
			TiXmlElement* objPosition = objectElement->FirstChildElement("position");
			objPosition->Attribute("x", &x);
			objPosition->Attribute("y", &y);

			// Load the size of the object.
			TiXmlElement* objSize = objectElement->FirstChildElement("size");
			objSize->Attribute("width", &width);
			objSize->Attribute("height", &height);

			hitBox.left = x;
			hitBox.top = y;
			hitBox.right = x + width;
			hitBox.bottom = y + height;

			// Load the object tag.
			tag = objectElement->Attribute("tag");

			// Load the object data.
			const char * c = objectElement->Attribute("data");
			if(c != nullptr)
				data = c;

			// Does the object have waypoint data?
			hasWaypoints = strcmp(objectElement->Attribute("hasWaypoints"), "True") == 0 ? true : false;
			useEvents = strcmp(objectElement->Attribute("useEvents"), "True") == 0 ? true : false;

			// If hasWaypoints is TRUE, continue to load waypoint data for the object.
			vector<POINT> waypoints;
			if(hasWaypoints == true)
			{
				TiXmlElement* waypointElement = objectElement->FirstChildElement("waypoint");

				//////////////////////////////////////////////////
				// Load all waypoints:
				while(waypointElement != nullptr)
				{
					POINT position;
					int x, y;

					waypointElement->Attribute("x", &x);
					waypointElement->Attribute("y", &y);

					position.x = x;
					position.y = y;

					waypoints.push_back(position);

					waypointElement = waypointElement->NextSiblingElement("waypoint");
				}
			}

			// If useEvents is TRUE, continue to load event data for the object.
			vector<EventPackage> events;
			if(useEvents == true)
			{
				TiXmlElement* eventElement = objectElement->FirstChildElement("event");

				while(eventElement != nullptr)
				{
					EventPackage package;

					package.name = eventElement->Attribute("name");

					TiXmlElement* tagElement = eventElement->FirstChildElement("tag");

					while(tagElement != nullptr)
					{
						package.tags.push_back(tagElement->GetText());
						tagElement = tagElement->NextSiblingElement("tag");
					}

					eventElement = eventElement->NextSiblingElement("event");

					events.push_back(package);
				}
			}

			// Create and send the object to the Object Manager.
			CreateGameobject(id, tag, data, hitBox, waypoints, events);

			// Load the next object.
			objectElement = objectElement->NextSiblingElement("object");
		}

		//////////////////////////////////////////////////
		// Load collision boxes:
		while(collisionElement != nullptr)
		{
			string tag;
			int x, y, width, height;
			bool canBeGrappled;

			// Load the collision box's tag.
			tag = collisionElement->Attribute("tag");

			// Load wether or not the collision box can be grappled.
			canBeGrappled = strcmp(collisionElement->Attribute("canBeGrappled"),
				"True") == 0 ? true : false;

			// Load the collision box's position.
			TiXmlElement* position = collisionElement->FirstChildElement("position");
			position->Attribute("x", &x);
			position->Attribute("y", &y);

			// Load the collision box's size.
			TiXmlElement* size = collisionElement->FirstChildElement("size");
			size->Attribute("width", &width);
			size->Attribute("height", &height);

			// Create the collision box's hit box.
			RECT hitBox;
			hitBox.left = x;
			hitBox.top = y;
			hitBox.right = hitBox.left + width;
			hitBox.bottom = hitBox.top + height;

			GameObject* obj = nullptr;

			if(tag == "conveyor belt right")
			{
				ConveyorBelt* belt = new ConveyorBelt();
				belt->SetTag(tag);
				belt->SetPosX((float)x);
				belt->SetPosY((float)y);
				belt->SetHitBox(hitBox);
				belt->SetCanBeGrappled(canBeGrappled);
				belt->setIsClockwise(true);
				obj = belt;

				ObjectManager::GetInstance()->AddObject(GAMEOBJECTS, obj);
			}
			else if( tag == "conveyor belt left" )
			{
				ConveyorBelt* belt = new ConveyorBelt();
				//TODO::Add in method to set direction
				belt->SetTag(tag);
				belt->SetPosX((float)x);
				belt->SetPosY((float)y);
				belt->SetHitBox(hitBox);
				belt->SetCanBeGrappled(canBeGrappled);
				belt->setIsClockwise(false);
				obj = belt;

				ObjectManager::GetInstance()->AddObject(GAMEOBJECTS, obj);
			}
			else if(tag == "enter door" || tag == "exit door")
			{
				GameObject* door = new GameObject();
				door->SetTag(tag);
				door->SetPosX((float)x);
				door->SetPosY((float)y);
				door->SetHitBox(hitBox);
				door->SetCanBeGrappled(canBeGrappled);
				obj = door;

				ObjectManager::GetInstance()->AddObject(GAMEOBJECTS, obj);
			}
			else
			{
				obj = new StaticObjects();
				obj->SetTag(tag);
				obj->SetPosX((float)x);
				obj->SetPosY((float)y);
				obj->SetHitBox(hitBox);
				obj->SetCanBeGrappled(canBeGrappled);

				ObjectManager::GetInstance()->AddObject(STATIC_OBJECTS, obj);
			}


			// Load the next collision box.
			collisionElement = collisionElement->NextSiblingElement("collision");
		}

		//////////////////////////////////////////////////
		// Load tiles and tile sets:
		if(tileMapElement != nullptr)
		{
			int mapWidth, mapHeight;// Will be used to calculate the world size for the camera.
			int tileWidth, tileHeight;
			std::map<int, int> tileSetImageIDs;

			tileMapElement->Attribute("width", &mapWidth);
			tileMapElement->Attribute("height", &mapHeight);
			tileMapElement->Attribute("tileWidth", &tileWidth);
			tileMapElement->Attribute("tileHeight", &tileHeight);

			// Set the world width and height for the camera.
			Camera::GetInstance()->SetWorldWidth(mapWidth * tileWidth);
			Camera::GetInstance()->SetWorldHeight(mapHeight * tileHeight);

			TiXmlElement* tileSetElement = tileMapElement->FirstChildElement("tileSet");
			TiXmlElement* tileElement = tileMapElement->FirstChildElement("tile");

			// Load all tileset images and store their imageIDs for the tiles.
			while(tileSetElement != nullptr)
			{
				// Get the name of the image.
				string imageName = tileSetElement->Attribute("image");
				int tileID = 0;
				tileSetElement->Attribute("tileID", &tileID);
				imageName.insert(0, "Textures\\");

				// Load the image and store the returned image ID.
				tileSetImageIDs.emplace(tileID, CSGD_TextureManager::GetInstance()->LoadTexture(imageName));

				// Load the next tile set.
				tileSetElement = tileSetElement->NextSiblingElement("tileSet");
			}

			// After all tile sets have been loaded, load all the tiles.
			while(tileElement != nullptr)
			{
				int id;
				int x, y;
				int srcX, srcY;

				// Load the tile attributes.
				tileElement->Attribute("x", &x);
				tileElement->Attribute("y", &y);
				tileElement->Attribute("srcX", &srcX);
				tileElement->Attribute("srcY", &srcY);
				tileElement->Attribute("id", &id);

				if(id != -1)
				{
					Tile* tile = new Tile();

					// Create the tile's hitbox.
					RECT hitBox;
					hitBox.left = x;
					hitBox.top = y;
					hitBox.right = hitBox.left + tileWidth;
					hitBox.bottom = hitBox.top + tileHeight;

					// Create the tile's source rect.
					RECT srcRect;
					srcRect.left = srcX;
					srcRect.top = srcY;
					srcRect.right = srcRect.left + tileWidth;
					srcRect.bottom = srcRect.top + tileHeight;

					// Set the tile's attributes.
					tile->SetPosX((float)x);
					tile->SetPosY((float)y);
					tile->SetHitBox(hitBox);
					tile->SetSourceRect(srcRect);
					tile->SetImageID(tileSetImageIDs.at(id));

					ObjectManager::GetInstance()->AddObject(TILES, tile);
				}

				// Load the next tile.
				tileElement = tileElement->NextSiblingElement("tile");
			}
		}

		//////////////////////////////////////////////////
		// Load particle emitters:
		//while(emitterElement != nullptr)
		//{
		//	int x, y;
		//	bool isActive;
		//	string filename;
		//	string tag;

		//	// Load the emitter's filename and tag;
		//	filename = emitterElement->Attribute("filename");
		//	tag = emitterElement->Attribute("tag");

		//	// Is it active on start?
		//	isActive = strcmp(emitterElement->Attribute("isActive"), "True") == 0 ? true : false;
		//	
		//	// Load the emitter's position.
		//	emitterElement->Attribute("x", &x);
		//	emitterElement->Attribute("y", &y);

		//	// TODO:
		//	//emitterManager->Load(tag, filename, isActive, x, y);

		//	// Load the next emitter.
		//	emitterElement = emitterElement->NextSiblingElement("emitter");
		//}

		curLevel = level;
	}
}

// UnloadLevel
//	- Unloads the currently stored level data from memory.
void LevelManager::UnloadLevel(void)
{
	objectManager->RemoveAllExceptPlayer();
	HelpInfoManager::GetInstance()->resetObjects();
}

// LoadNextLevel
//	- If there is a level following the one currently loaded,
//	  the current level is unloaded, and the next level
//	  is loaded.
//	- RETURNS TRUE if there was a subsequent level.
//	- RETURNS FALSE if there is no subsequent level.
bool LevelManager::LoadNextLevel(void)
{
	if(curLevel + 1 < totalLevels)
	{
		++curLevel;
		HelpInfoManager::GetInstance()->addObject("Player");
		LoadLevel(curLevel);
		return true;
	}
	return false;
}

// CreateGameobject
//	- Used to create a gameobject based on the tag that is passed in. The function
//	  creates the object, initializes the proper data, and adds it to the Object Manager.
void LevelManager::CreateGameobject(string id, string tag, string data, RECT hitBox,
									vector<POINT>& waypoints, vector<EventPackage>& events)
{
	GameObject* object = new GameObject();

	if(id == "Generator")
	{
		Generator* gen = new Generator();
		gen->SetPoweredImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\GenPowered.png")));
		gen->SetUnpoweredImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\GenOff.png")));
		delete object;
		object = gen;

	}
	if(id == "Security Cannon")
	{
		SecurityCannon* secc = new SecurityCannon();
		secc->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\Lasercannon.png")));
		secc->SetTurretBaseID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\TurretBase.png")));
		delete object;
		object = secc;

	}
	if(id == "Crusher" )
	{
		Crusher* cru = new Crusher();
		cru->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\crusher.png")));
		delete object;
		object = cru;

	}
	if(id == "Machine Broken")
	{
		MachineObj* mob = new MachineObj();
		mob->SetRepairedImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\GeneratorActive.png")));
		mob->SetBrokenImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\GeneratorInactive.png")));
		delete object;
		object = mob;
	}
	if(id == "Check Point")
	{
		CheckPoint* cpt = new CheckPoint();
		delete object;
		object = cpt;

	}
	if(id == "Button")
	{
		Button* btn = new Button();
		btn->SetActiveImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\button active.png")));
		btn->SetInactiveImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\button inactive.png")));
		delete object;
		object = btn;
	}
	else if(id == "Moving Platform")
	{
		MovingPlatform* obj = new MovingPlatform();
		obj->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\moving platform.png")));
		for(unsigned int i = 0; i < waypoints.size(); ++i)
			obj->AddWaypoint(waypoints[i]);
		if(GetObjectDataBool(data.c_str(), "isNotPowered"))
		{
			obj->SetIsPowered(false);
		}
		for(unsigned int i = 0; i < events.size(); ++i)
			obj->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = obj;
	}
	else if(id == "Ice Block")
	{
		IceBlock* ice = new IceBlock();
		ice->SetCanBeGrappled(false);
		ice->SetSaveHitBox(hitBox);
		ice->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\ice block.png")));
		delete object;
		object = ice;
	}
	else if(id == "Ice Layer Left")
	{
		IceLayer* ice = new IceLayer();
		ice->SetCanBeGrappled(false);
		ice->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\ice layer left.png")));
		ice->SetPuddleImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\puddle left.png")));
		delete object;
		object = ice;
	}
	else if(id == "Ice Layer Right")
	{
		IceLayer* ice = new IceLayer();
		ice->SetCanBeGrappled(false);
		ice->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\ice layer right.png")));
		ice->SetPuddleImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\puddle right.png")));
		delete object;
		object = ice;
	}
	else if(id == "Ice Layer Center")
	{
		IceLayer* ice = new IceLayer();
		ice->SetCanBeGrappled(false);
		ice->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\ice layer center.png")));
		ice->SetPuddleImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\puddle center.png")));
		delete object;
		object = ice;
	}
	else if(id == "Wood Box")
	{
		WoodBox* obj = new WoodBox();
		obj->SetCanBeGrappled(false);
		obj->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\wood box.png")));
		EmitterManager::GetInstance()->Load(tag, "box_fire.xml", false, (float)hitBox.left, (float)hitBox.top);
		delete object;
		object = obj;
	}
	else if(id == "Metal Box")
	{
		MetalBox* obj = new MetalBox();
		obj->SetCanBeGrappled(false);
		obj->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\metal box.png")));
		delete object;
		object = obj;
	}
	else if(id == "Conveyor Left")
	{
		object->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\conveyor left.png")));
		object->SetTag(tag);
		object->SetPosX((float)hitBox.left);
		object->SetPosY((float)hitBox.top);
		object->SetHitBox(hitBox);
		object->SetStartPosition((float)hitBox.left, (float)hitBox.top);
		object->SetCheckPointPosition((float)hitBox.left, (float)hitBox.top);
		ObjectManager::GetInstance()->AddObject(TILES, object);
		return;
	}
	else if(id == "Conveyor Center")
	{
		object->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\conveyor center.png")));
		object->SetTag(tag);
		object->SetPosX((float)hitBox.left);
		object->SetPosY((float)hitBox.top);
		object->SetHitBox(hitBox);
		object->SetStartPosition((float)hitBox.left, (float)hitBox.top);
		object->SetCheckPointPosition((float)hitBox.left, (float)hitBox.top);
		ObjectManager::GetInstance()->AddObject(TILES, object);
		return;
	}
	else if(id == "Conveyor Right")
	{
		object->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\conveyor right.png")));
		object->SetTag(tag);
		object->SetPosX((float)hitBox.left);
		object->SetPosY((float)hitBox.top);
		object->SetHitBox(hitBox);
		object->SetStartPosition((float)hitBox.left, (float)hitBox.top);
		object->SetCheckPointPosition((float)hitBox.left, (float)hitBox.top);
		ObjectManager::GetInstance()->AddObject(TILES, object);
		return;
	}
	else if(id == "Gate (Verticle)")
	{
		Gate* gate = new Gate();
		gate->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\gate.png")));
		gate->SetHitBox(hitBox);
		gate->SetMinHeight(0);
		gate->SetMaxHeight(hitBox.bottom - hitBox.top);
		gate->SetVertical(true);

		bool StartOpen = GetObjectDataBool(data.c_str(), "StartOpen");

		if( StartOpen == true )
		{
			gate->SetStartOpen(true);
		}

		for(unsigned int i = 0; i < events.size(); ++i)
			gate->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = gate;
	}
	else if(id == "Gate (Horizontal)")
	{
		Gate* gate = new Gate();
		gate->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\gate horizontal.png")));
		gate->SetHitBox(hitBox);
		gate->SetMinHeight(0);
		gate->SetMaxHeight(hitBox.right - hitBox.left);
		gate->SetVertical(false);

		bool StartOpen = GetObjectDataBool(data.c_str(), "StartOpen");

		if( StartOpen == true )
		{
			gate->SetStartOpen(true);
		}

		for(unsigned int i = 0; i < events.size(); ++i)
			gate->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = gate;
	}
	else if(id == "Gate (Conditional)")
	{
		ConditionalGate* gate = new ConditionalGate();
		gate->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\gate horizontal.png")));
		gate->SetHitBox(hitBox);
		gate->SetMinHeight(0);
		gate->SetMaxHeight(hitBox.bottom - hitBox.top);
		gate->SetStartHeight(hitBox.bottom - hitBox.top);
		gate->SetVertical(true);

		int maxXCount = GetObjectDataInt(data.c_str(), "maxXCount");
		int maxYCount = GetObjectDataInt(data.c_str(), "maxYCount");

		gate->SetMaxXCount( maxXCount );
		gate->SetMaxYCount( maxYCount );

		for(unsigned int i = 0; i < events.size(); ++i)
			gate->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = gate;
	}
	else if(id == "Saw")
	{
		Saw* saw = new Saw();
		saw->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\saw.png")));
		delete object;
		//RECT updateHit = saw->GetHitBox();
		//updateHit.right = updateHit.left + 128;
		//saw->SetHitBox(updateHit);
		object = saw;
	}
	else if(id == "Fan Left")
	{
		Fan* fan = new Fan(400.0f);
		fan->SetDirection(1, 0);
		fan->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\fan left.png")));
		for(unsigned int i = 0; i < waypoints.size(); ++i)
			fan->AddWaypoint(waypoints[i]);
		delete object;
		object = fan;
	}
	else if(id == "Fan Right")
	{
		Fan* fan = new Fan(400.0f);
		fan->SetDirection(-1, 0);
		fan->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\fan right.png")));
		for(unsigned int i = 0; i < waypoints.size(); ++i)
			fan->AddWaypoint(waypoints[i]);
		delete object;
		object = fan;
	}
	else if(id == "Fan Top")
	{
		Fan* fan = new Fan(400.0f);
		fan->SetDirection(0, 1);
		fan->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\fan top.png")));
		for(unsigned int i = 0; i < waypoints.size(); ++i)
			fan->AddWaypoint(waypoints[i]);
		delete object;
		object = fan;
	}
	else if(id == "Fan Bottom")
	{
		Fan* fan = new Fan(400.0f);
		fan->SetDirection(0, -1);
		fan->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\fan bottom.png")));
		for(unsigned int i = 0; i < waypoints.size(); ++i)
			fan->AddWaypoint(waypoints[i]);
		delete object;
		object = fan;
	}
	else if (id == "Flame Jet")
	{
		//TODO: make the image for flame jet, update name if necessary
		EmitterManager::GetInstance()->Load("flameJet","flameJet.xml",true,(float)hitBox.left,(float)hitBox.top);
		FlameJet* flame = new FlameJet();
		flame->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\flame jet top.png")));
		delete object;
		object = flame;
	}
	else if(id == "Hologram")
	{
		Hologram* hologram = new Hologram();

		for(unsigned int i = 0; i < events.size(); ++i)
			hologram->addEventToMap(events[i].name, events[i].tags);

		for(int i = 1; i < 7; ++i)
			hologram->AddImage(CSGD_TextureManager::GetInstance()->LoadTexture(string("Textures\\Tutorials\\Level1\\") + GetObjectData(data.c_str(), to_string(i)) + ".png"));

		hologram->SetShowOnKill(GetObjectDataBool(data.c_str(), "showAfterDeath"));

		delete object;
		object = hologram;

		object->SetTag(tag);
		object->SetPosX((float)hitBox.left);
		object->SetPosY((float)hitBox.top);
		object->SetHitBox(hitBox);
		object->SetStartPosition((float)hitBox.left, (float)hitBox.top);
		object->SetCheckPointPosition((float)hitBox.left, (float)hitBox.top);

		ObjectManager::GetInstance()->AddObject(TILES, object);
		return;
	}
	else if(id == "Radiation Barrel")
	{
		RadiationBarrel* barrel = new RadiationBarrel();
		barrel->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\radiation barrel.png")));
		barrel->SetCanBeGrappled(false);
		barrel->SetRange(200.0f);
		delete object;
		object = barrel;
	}
	else if(id == "Laser Emitter Top")
	{
		LaserEmitter* laser = new LaserEmitter();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser emitter top.png")));
		laser->SetCanBeGrappled(false);
		laser->SetRange((float)INT_MAX);
		laser->SetDirection(0, 1);

		bool StartPower = GetObjectDataBool(data.c_str(), "StartPower");

		if( StartPower == true )
		{
			laser->SetPoweredOnStart(true);
		}
		else
			laser->SetPoweredOnStart(false);

		if(GetObjectDataBool(data.c_str(),"isNotPowered"))
			laser->SetIsPowered(false);
		for(unsigned int i = 0; i < events.size(); ++i)
			laser->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = laser;
	}
	else if(id == "Laser Emitter Bottom")
	{
		LaserEmitter* laser = new LaserEmitter();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser emitter bottom.png")));
		laser->SetCanBeGrappled(false);
		laser->SetRange((float)INT_MAX);
		laser->SetDirection(0, -1);

		bool StartPower = GetObjectDataBool(data.c_str(), "StartPower");

		if( StartPower == true )
		{
			laser->SetPoweredOnStart(true);
		}
		else
			laser->SetPoweredOnStart(false);

		if(GetObjectDataBool(data.c_str(),"isNotPowered"))
			laser->SetIsPowered(false);
		for(unsigned int i = 0; i < events.size(); ++i)
			laser->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = laser;
	}
	else if(id == "Laser Emitter Left")
	{
		LaserEmitter* laser = new LaserEmitter();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser emitter left.png")));
		laser->SetCanBeGrappled(false);
		laser->SetRange((float)INT_MAX);
		laser->SetDirection(1, 0);

		bool StartPower = GetObjectDataBool(data.c_str(), "StartPower");

		if( StartPower == true )
		{
			laser->SetPoweredOnStart(true);
		}
		else
			laser->SetPoweredOnStart(false);

		if(GetObjectDataBool(data.c_str(),"isNotPowered"))
			laser->SetIsPowered(false);
		for(unsigned int i = 0; i < events.size(); ++i)
			laser->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = laser;
	}
	else if(id == "Laser Emitter Right")
	{
		LaserEmitter* laser = new LaserEmitter();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser emitter right.png")));
		laser->SetCanBeGrappled(false);
		laser->SetRange((float)INT_MAX);
		laser->SetDirection(-1, 0);

		bool StartPower = GetObjectDataBool(data.c_str(), "StartPower");

		if( StartPower == true )
		{
			laser->SetPoweredOnStart(true);
		}
		else
			laser->SetPoweredOnStart(false);

		if(GetObjectDataBool(data.c_str(),"isNotPowered"))
			laser->SetIsPowered(false);
		for(unsigned int i = 0; i < events.size(); ++i)
			laser->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = laser;
	}
	else if(id == "Laser Reflector Bottom Left")
	{
		LaserReflector* reflector = new LaserReflector();
		reflector->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser reflector bottom left.png")));
		reflector->SetCanBeGrappled(false);
		reflector->SetNormal(-1, 1);
		reflector->Rotate(0.0f);
		reflector->AutoRotate(GetObjectDataBool(data.c_str(), "autoRotate"));
		reflector->RotateClockwise(GetObjectDataBool(data.c_str(), "Clockwise"));
		for(unsigned int i = 0; i < events.size(); ++i)
			reflector->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = reflector;
	}
	else if(id == "Laser Reflector Bottom Right")
	{
		LaserReflector* reflector = new LaserReflector();
		reflector->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser reflector bottom left.png")));
		reflector->SetCanBeGrappled(false);
		reflector->SetNormal(-1, 1);
		reflector->Rotate(-3.1415926f * 0.5f);
		reflector->AutoRotate(GetObjectDataBool(data.c_str(), "autoRotate"));
		reflector->RotateClockwise(GetObjectDataBool(data.c_str(), "Clockwise"));
		for(unsigned int i = 0; i < events.size(); ++i)
			reflector->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = reflector;
	}
	else if(id == "Laser Reflector Top Left")
	{
		LaserReflector* reflector = new LaserReflector();
		reflector->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser reflector bottom left.png")));
		reflector->SetCanBeGrappled(false);
		reflector->SetNormal(-1, 1);
		reflector->Rotate(3.1415926f * 0.5f);
		reflector->AutoRotate(GetObjectDataBool(data.c_str(), "autoRotate"));
		reflector->RotateClockwise(GetObjectDataBool(data.c_str(), "Clockwise"));
		for(unsigned int i = 0; i < events.size(); ++i)
			reflector->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = reflector;
	}
	else if(id == "Laser Reflector Top Right")
	{
		LaserReflector* reflector = new LaserReflector();
		reflector->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser reflector bottom left.png")));
		reflector->SetCanBeGrappled(false);
		reflector->SetNormal(-1, 1);
		reflector->Rotate(3.1415926f);
		reflector->AutoRotate(GetObjectDataBool(data.c_str(), "autoRotate"));
		reflector->RotateClockwise(GetObjectDataBool(data.c_str(), "Clockwise"));
		for(unsigned int i = 0; i < events.size(); ++i)
			reflector->addEventToMap(events[i].name, events[i].tags);
		delete object;
		object = reflector;
	}
	else if(id == "Laser Receiver Top")
	{
		LaserReceiver* laser = new LaserReceiver();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser receiver top.png")));
		laser->SetCanBeGrappled(false);
		delete object;
		object = laser;
	}
	else if(id == "Laser Receiver Bottom")
	{
		LaserReceiver* laser = new LaserReceiver();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser receiver bottom.png")));
		laser->SetCanBeGrappled(false);
		delete object;
		object = laser;
	}
	else if(id == "Laser Receiver Left")
	{
		LaserReceiver* laser = new LaserReceiver();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser receiver left.png")));
		laser->SetCanBeGrappled(false);
		delete object;
		object = laser;
	}
	else if(id == "Laser Receiver Right")
	{
		LaserReceiver* laser = new LaserReceiver();
		laser->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\laser receiver right.png")));
		laser->SetCanBeGrappled(false);
		delete object;
		object = laser;
	}
	else if(id == "Trip Wire Top")
	{
		TripWire* wire = new TripWire();
		wire->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\trip wire top.png")));
		wire->SetCanBeGrappled(false);
		tVector2D directionToCast;
		directionToCast.fX = 0; directionToCast.fY = 1;
		wire->SetDirection(directionToCast);

		wire->SetPosX((float)hitBox.left);
		wire->SetPosY((float)hitBox.top);
		tVector2D startPos;
		startPos.fX = wire->GetPosX(); startPos.fY = wire->GetPosY();
		startPos.fX += 15.0f;
		startPos.fY -= 1.0f;
		wire->SetStart(startPos);

		delete object;
		object = wire;
	}
	else if(id == "Trip Wire Bottom")
	{
		TripWire* wire = new TripWire();
		wire->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\trip wire bottom.png")));
		wire->SetCanBeGrappled(false);
		tVector2D directionToCast;
		directionToCast.fX = 0; directionToCast.fY = -1;
		wire->SetDirection(directionToCast);

		wire->SetPosX((float)hitBox.left);
		wire->SetPosY((float)hitBox.top);
		tVector2D startPos;
		startPos.fX = wire->GetPosX(); startPos.fY = wire->GetPosY();
		startPos.fX += 15.0f;
		startPos.fY -= 1.0f;
		wire->SetStart(startPos);

		delete object;
		object = wire;
	}
	else if(id == "Trip Wire Left")
	{
		TripWire* wire = new TripWire();
		wire->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\trip wire left.png")));
		wire->SetCanBeGrappled(false);
		tVector2D directionToCast;
		directionToCast.fX = 1; directionToCast.fY = 0;
		wire->SetDirection(directionToCast);

		wire->SetPosX((float)hitBox.left);
		wire->SetPosY((float)hitBox.top);
		tVector2D startPos;
		startPos.fX = wire->GetPosX(); startPos.fY = wire->GetPosY();
		startPos.fX += 15.0f;
		startPos.fY += 15.0f;
		wire->SetStart(startPos);

		delete object;
		object = wire;
	}
	else if(id == "Trip Wire Right")
	{
		TripWire* wire = new TripWire();
		wire->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\trip wire right.png")));
		wire->SetCanBeGrappled(false);
		tVector2D directionToCast;
		directionToCast.fX = -1; directionToCast.fY = 0;
		wire->SetDirection(directionToCast);

		wire->SetPosX((float)hitBox.left);
		wire->SetPosY((float)hitBox.top);
		tVector2D startPos;
		startPos.fX = wire->GetPosX(); startPos.fY = wire->GetPosY();
		startPos.fX += 2.0f;
		startPos.fY += 15.0f;
		wire->SetStart(startPos);

		delete object;
		object = wire;
	}
	else if(id == "Water")
	{
		Water* water = new Water();
		water->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\water.png")));
		water->SetCanBeGrappled(false);
		if(GetObjectDataBool(data.c_str(), "Frozen"))
		{
			water->Freeze();
		}
		delete object;
		object = water;
	}
	else if(id == "Water (Surface)")
	{
		Water* water = new Water();
		water->SetImageID(CSGD_TextureManager::GetInstance()->LoadTexture(_T("Textures\\Objects\\water surface.png")));
		water->SetCanBeGrappled(false);
		if(GetObjectDataBool(data.c_str(), "Frozen"))
		{
			water->Freeze();
		}
		delete object;
		object = water;
	}

	HelpInfoManager::GetInstance()->addObject(id);


	object->SetTag(tag);
	object->SetPosX((float)hitBox.left);
	object->SetPosY((float)hitBox.top);
	object->SetHitBox(hitBox);
	object->SetStartPosition((float)hitBox.left, (float)hitBox.top);
	object->SetCheckPointPosition((float)hitBox.left, (float)hitBox.top);

	objectManager->AddObject(GAMEOBJECTS, object);
}

string GetObjectData(const char* data, string tag)
{
	if(data[0] == '\0')
		return string("");

	bool search = true;
	unsigned int i = 0;

	while(search == true)
	{
		string text = "";
		for( ; data[i] != '\0' && data[i] != '='; text += data[i], ++i);

		if(data[i] == '\0')
		{
			search = false;
			continue;
		}

		if(text == tag)
		{
			string value = "";
			for(++i; data[i] != '\0' && data[i] != ' '; value += data[i], ++i);

			return value;
		}

		for( ; data[i] != '\0' && data[i] != ' '; ++i);

		if(data[i] == '\0')
			search = false;

		++i;
	}
	return string("");
}
int GetObjectDataInt(const char* data, string tag)
{
	if(data[0] == '\0')
		return INT_MAX;

	bool search = true;
	unsigned int i = 0;

	while(search == true)
	{
		string text = "";
		for( ; data[i] != '\0' && data[i] != '='; text += data[i], ++i);

		if(data[i] == '\0')
		{
			search = false;
			continue;
		}

		if(text == tag)
		{
			string value = "";
			for(++i; data[i] != '\0' && data[i] != ' '; value += data[i], ++i);

			return atoi(value.c_str());
		}

		for( ; data[i] != '\0' && data[i] != ' '; ++i);

		if(data[i] == '\0')
			search = false;

		++i;
	}
	return 0;
}
bool GetObjectDataBool(const char* data, string tag)
{
	if(data[0] == '\0')
		return false;

	bool search = true;
	unsigned int i = 0;

	while(search == true)
	{
		string text = "";
		for( ; data[i] != '\0' && data[i] != '='; text += data[i], ++i);

		if(data[i] == '\0')
		{
			search = false;
			continue;
		}

		if(text == tag)
		{
			string value = "";
			for(++i; data[i] != '\0' && data[i] != ' '; value += data[i], ++i);

			return (value == "true") ? true : false;
		}

		for( ; data[i] != '\0' && data[i] != ' '; ++i);

		if(data[i] == '\0')
			search = false;

		++i;
	}
	return false;
}
